/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gps.decoder;

import pe.gps.record.Record;
import pe.gps.record.RecordAlarma;
import pe.gps.record.Record_GT06N;
import pe.gps.util.Crc;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import pe.gps.log.Log;

/**
 *
 * @author romulogalindo
 */
public class GT06N extends Decoder {

    private int protocol_number;
    private boolean valid;
    private boolean charge;
    private boolean oil_electricity;
    private boolean gps_tracking;
    private int nivel_voltaje;
    private String acc;
    private short serial_number;

    public GT06N() {
        this.record = new Record_GT06N();
    }

    @Override
    public void decode(ByteBuffer buffer) {
        try {
            state = 0;
            buffer.position(3);
            protocol_number = Integer.valueOf(buffer.get());

            if (protocol_number == 1) {
                Log.log("[GT06N]Logueo", Log.DEBUG);
                //imei
                byte[] imei_byte = new byte[]{buffer.get(), buffer.get(), buffer.get(), buffer.get(), buffer.get(), buffer.get(), buffer.get(), buffer.get()};
                imei = readImei(imei_byte);
                record.setId(imei);
                getFooter(buffer);
                state = 1;
                record.setType(state);
            } else if (protocol_number == 18) {
//                Log.log("[GT06N]Data<---------INICIO", Log.DEBUG);
                state = 2;

                //fecha
                Calendar time = Calendar.getInstance();
                time.clear();
//                Log.log("[GT06N]Data<---------Procesando", Log.DEBUG);
                time.set(Calendar.YEAR, 2000 + (int) buffer.get());
                time.set(Calendar.MONTH, (int) buffer.get() - 1);
                time.set(Calendar.DAY_OF_MONTH, (int) buffer.get());
                time.set(Calendar.HOUR, (int) buffer.get());
                time.set(Calendar.MINUTE, (int) buffer.get());
                time.set(Calendar.SECOND, (int) buffer.get());
                record.getPosicion().setFecha(time.getTime());

//                Log.log("[GT06N]Data<---------Procesando2", Log.DEBUG);
                getGpsInfo(buffer);
//                Log.log("[GT06N]Data<---------Procesando3", Log.DEBUG);

                getLbsInfo(buffer);
//                Log.log("[GT06N]Data<---------Procesando4", Log.DEBUG);

                getFooter(buffer);

                record.setType(state);
//                Log.log("[GT06N]Data<-----FIN] con state=" + state, Log.DEBUG);
            } else if (protocol_number == 19) {
//                Log.log("[GT06N]Heartbeat", Log.DEBUG);
                getStatusInfo(buffer);
                getFooter(buffer);
                state = 4;
                if (record.getAlarma().getAlarma() != null && record.getAlarma().getAlarma() != 0) {
                    state = 5;
                }
                record.setType(state);
            } else if (protocol_number == 22) {
//                Log.log("[GT06N]Heartbeat", Log.DEBUG);
                Calendar time = Calendar.getInstance();
                time.clear();
                time.set(Calendar.YEAR, 2000 + Integer.valueOf(buffer.get()));
                time.set(Calendar.MONTH, Integer.valueOf(buffer.get()) - 1);
                time.set(Calendar.DAY_OF_MONTH, Integer.valueOf(buffer.get()));
                time.set(Calendar.HOUR, Integer.valueOf(buffer.get()));
                time.set(Calendar.MINUTE, Integer.valueOf(buffer.get()));
                time.set(Calendar.SECOND, Integer.valueOf(buffer.get()));
                record.getPosicion().setFecha(time.getTime());

                getGpsInfo(buffer);

                getLbsInfo(buffer);

                getStatusInfo(buffer);

                getFooter(buffer);

                state = 3;
                if (record.getAlarma().getAlarma() != null && record.getAlarma().getAlarma() != 0) {
                    state = 8;
                }
                record.setType(state);
            }
        } catch (Exception ep) {
            System.out.println("[GT06N]Error desencriptando: " + ep);
            ep.printStackTrace();
            state = 2;
        }
    }

    private String readImei(byte[] buffer) {
        int b = buffer[0];
        StringBuilder imei = new StringBuilder();
        imei.append(b & 0x0F);
        for (int i = 0; i < 7; i++) {
            b = buffer[i + 1];
            imei.append((b & 0xF0) >> 4);
            imei.append(b & 0x0F);
        }
        return imei.toString();
    }

    private void getGpsInfo(ByteBuffer buffer) {
        record.getPosicion().setCant_satelites(Integer.valueOf(buffer.get()));
        record.getPosicion().setLatitud(buffer.getInt() / (60.0 * 30000.0));
        record.getPosicion().setLongitud(buffer.getInt() / (60.0 * 30000.0));
        record.getPosicion().setVelocidad(Integer.valueOf(buffer.get()));

        int union = buffer.getShort();
        record.getPosicion().setDireccion((int) (union & 0x03FF));
        valid = (union & 0x1000) != 0;
        if ((union & 0x0400) == 0) {
            record.getPosicion().setLatitud(-record.getPosicion().getLatitud());
        }
        if ((union & 0x0800) != 0) {
            record.getPosicion().setLongitud(-record.getPosicion().getLongitud());
        }
    }

    private void getStatusInfo(ByteBuffer buffer) {
        char[] information_binary = Integer.toBinaryString(256 + (int) buffer.get()).substring(1).toCharArray();

        record.getEstado().setBloqueado((information_binary[0] == '1'));
        gps_tracking = information_binary[1] == '1';
        String alarma1 = new String(new char[]{information_binary[2], information_binary[3], information_binary[4]});
        switch (alarma1) {
            case "100":
                record.getAlarma().setAlarma(RecordAlarma.SOS);
                break;
            case "010":
                record.getAlarma().setAlarma(RecordAlarma.POWER_CUT);
                break;
        }
        charge = information_binary[5] == '1';
        record.getEstado().setBatdis(!charge);
        acc = information_binary[6] == '1' ? "high" : "low";
        record.getEstado().setCarga_bateria(procesCharge(Integer.valueOf(buffer.get()), 7));

        record.getEstado().setSenal_gsm(procesSenal(Integer.valueOf(buffer.get()), 0, 4));
        Integer alarma2 = Integer.valueOf(buffer.get());
        switch (alarma2) {
            case 1:
                record.getAlarma().setAlarma(RecordAlarma.SOS);
                break;
            case 2:
                record.getAlarma().setAlarma(RecordAlarma.POWER_CUT);
                break;
        }
        buffer.get();

    }

    private void getLbsInfo(ByteBuffer buffer) {
        if (protocol_number == 22) {
            buffer.get();
        }
        buffer.get();
        buffer.get();
        buffer.get();
        buffer.get();
        buffer.get();
        buffer.get();
        buffer.get();
        buffer.get();
    }

    private void getFooter(ByteBuffer buffer) {
        serial_number = buffer.getShort();
        buffer.get();
        buffer.get();
    }

    private Character procesSenal(int posicion, int menor, int mayor) {
        int capacidad = mayor - menor;
        capacidad++;
        Map<Integer, Character> mapa = new HashMap<>();
        mapa.put(0, 'E');
        mapa.put(1, 'D');
        mapa.put(2, 'C');
        mapa.put(3, 'B');
        mapa.put(4, 'A');
        double n1 = (double) capacidad / (double) 4;
        int n2 = (int) Math.round((double) posicion / n1);
        return mapa.get(n2);
    }

    private Integer procesCharge(int posicion, int max) {
        double n1 = posicion * 100;
        return (int) Math.round(n1 / (double) max);
    }

    @Override
    public ByteBuffer response() {
        if (state == 0) {
            return null;
        } else {
            if (protocol_number == 1) {
                ByteBuffer crc_bef = ByteBuffer.allocate(4);
                crc_bef.put((byte) 0x05);
                crc_bef.put((byte) 0x01);
                crc_bef.putShort(serial_number);
                crc_bef.flip();

                ByteBuffer buffer = ByteBuffer.allocate(10);
                buffer.put((byte) 0x78);
                buffer.put((byte) 0x78);
                buffer.put((byte) 0x05);
                buffer.put((byte) protocol_number);
                buffer.putShort(serial_number);
                buffer.putShort((short) Crc.crc16Ccitt(crc_bef));
                buffer.put((byte) 0x0D);
                buffer.put((byte) 0x0A);

                buffer.flip();
                return buffer;
            } else if (protocol_number == 19) {
                ByteBuffer crc_bef = ByteBuffer.allocate(4);
                crc_bef.put((byte) 0x05);
                crc_bef.put((byte) 0x13);
                crc_bef.putShort(serial_number);
                crc_bef.flip();

                ByteBuffer buffer = ByteBuffer.allocate(10);
                buffer.put((byte) 0x78);
                buffer.put((byte) 0x78);
                buffer.put((byte) 0x05);
                buffer.put((byte) protocol_number);
                buffer.putShort(serial_number);
                buffer.putShort((short) Crc.crc16Ccitt(crc_bef));
                buffer.put((byte) 0x0D);
                buffer.put((byte) 0x0A);

                buffer.flip();
                return buffer;
            } else if (protocol_number == 22) {
                ByteBuffer crc_bef = ByteBuffer.allocate(4);
                crc_bef.put((byte) 0x05);
                crc_bef.put((byte) 0x16);
                crc_bef.putShort(serial_number);
                crc_bef.flip();

                ByteBuffer buffer = ByteBuffer.allocate(10);
                buffer.put((byte) 0x78);
                buffer.put((byte) 0x78);
                buffer.put((byte) 0x05);
                buffer.put((byte) protocol_number);
                buffer.putShort(serial_number);
                buffer.putShort((short) Crc.crc16Ccitt(crc_bef));
                buffer.put((byte) 0x0D);
                buffer.put((byte) 0x0A);

                buffer.flip();
                return buffer;
            } else {
                return null;
            }

        }
    }

    @Override
    public String toString() {
        return "{ID=" + record.getId() + ",POSICION=" + record.getPosicion() + ",ESTADO=" + record.getEstado() + "}";
    }

    @Override
    public List<Record> decoder(ByteBuffer buffer) {
        decode(buffer);
        List<Record> records = new ArrayList<>();
        records.add(record);
        return records;
    }

    @Override
    public List<Record> decoderIMEI(ByteBuffer buffer) {

        return null;
    }
}
